﻿using System;
using System.IO;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;

namespace uTILLIty.ADExtractor.Core.Extensions
{
	public static class ObjectExtensions
	{

		/// <summary>
		/// Retrieves the schema saved as an assembly-ressource
		/// </summary>
		/// <typeparam name="T">The namespace and assembly of the supplied type to look for the schema-resource</typeparam>
		/// <param name="resourceKey">The name of the resource within the namespace and assembly of the provided <typeparamref name="T">type</typeparamref></param>
		/// <returns>A new instance of the schema loaded from the assembies resources</returns>
		public static XmlSchema GetSchemaResource<T>(string resourceKey)
		{
			using (Stream data = typeof(T).Assembly.GetManifestResourceStream(typeof(T).Namespace + "." + resourceKey))
			{
				if (data == null)
					throw new NotSupportedException(string.Format("Cannot locate resource '{0}'", resourceKey));

				var schema = XmlSchema.Read(data, null);
				return schema;
			}
		}

		public static void XmlSerialize(this object target, Stream outputStream)
		{
			var serializer = new XmlSerializer(target.GetType());
			serializer.Serialize(outputStream, target);
		}

		/// <summary>
		/// Creates a new object by deserializing the <paramref name="configData"/> supplied
		/// </summary>
		/// <param name="configData">a stream representing the XML file to deserialize</param>
		/// <param name="schemas">an optional list of schemas to use for validating the <paramref name="configData"/></param>
		/// <returns>A new instance of <typeparam name="T"></typeparam></returns>
		public static T Load<T>(Stream configData, XmlSchemaSet schemas) where T : class
		{
			if (configData == null)
				throw new ArgumentNullException("configData");

			var settings = new XmlReaderSettings { ValidationType = ValidationType.None };
			if (schemas != null)
			{
				settings.ValidationEventHandler += OnValidationEvent;
				settings.ValidationType = ValidationType.Schema;
				settings.Schemas.Add(schemas);
			}

			using (var reader = XmlReader.Create(configData, settings))
			{
				return Load<T>(reader);
			}
		}

		/// <summary>
		/// Creates a new object by deserializing the <paramref name="reader"/> supplied
		/// </summary>
		/// <param name="reader">representing the XML to be deserialized</param>
		/// <returns>A new instance of <typeparam name="T"></typeparam></returns>
		public static T Load<T>(XmlReader reader) where T : class
		{
			var serializer = new XmlSerializer(typeof (T));
			var output = (T) serializer.Deserialize(reader);
			return output;
		}

		private static void OnValidationEvent(object sender, ValidationEventArgs e)
		{
			switch (e.Severity)
			{
				case XmlSeverityType.Error:
					throw new XmlSchemaValidationException(e.Message, e.Exception);
			}
		}

	}
}